package com.house.service.service.impl;

import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.Page;
import com.house.common.context.BaseContext;
import com.house.common.context.Dictionaries;
import com.house.common.context.RedisContext;
import com.house.common.exception.HouseException;
import com.house.common.result.HttpCodeEnum;
import com.house.model.dto.HouseDto;
import com.house.model.dto.HouseLocationDto;
import com.house.model.entity.Collect;
import com.house.model.entity.House;
import com.house.model.vo.HouseInfoVo;
import com.house.model.vo.HouseVo;
import com.house.model.vo.HouseVo;
import com.house.model.vo.SearchHouseVo;
import com.house.service.mapper.CollectMapper;
import com.house.service.mapper.HouseImageMapper;
import com.house.service.mapper.HouseMapper;
import com.house.service.service.IHouseService;
import org.apache.ibatis.annotations.Param;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.geo.GeoPoint;
import org.elasticsearch.common.unit.DistanceUnit;
import org.elasticsearch.index.query.GeoDistanceQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.text.DecimalFormat;
import java.util.*;

@Service
public class HouseServiceImpl extends ServiceImpl<HouseMapper,House> implements IHouseService {
    @Autowired
    private HouseMapper houseMapper;

    @Autowired
    private HouseImageMapper houseImageMapper;

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    @Autowired
    private RedisTemplate<String,Object> redisTemplate;



    @Override
    @Transactional
    public List<SearchHouseVo> searchHouseList(String addr) {
        // 从redis中获取这个搜索词，如果没有则添加分数设置为1，如果有则分数加一
        Double score = redisTemplate.opsForZSet().score(RedisContext.HOTSEARCH, addr);
        if (score == null) {
            redisTemplate.opsForZSet().add(RedisContext.HOTSEARCH,addr,1);
        }else {
            redisTemplate.opsForZSet().incrementScore(RedisContext.HOTSEARCH,addr,1);
        }
        ArrayList<SearchHouseVo> searchHouseVos = new ArrayList<>();
        SearchRequest request = new SearchRequest("house");
        request.source().query(QueryBuilders.multiMatchQuery(addr,"houseTitle","houseTitle","address"));
        try {
            SearchResponse search = restHighLevelClient.search(request, RequestOptions.DEFAULT);
            for (SearchHit hit : search.getHits()){
                HouseVo houseVo = JSONUtil.toBean(hit.getSourceAsString(), HouseVo.class);
                SearchHouseVo searchHouseVo = new SearchHouseVo();
                BeanUtils.copyProperties(houseVo,searchHouseVo);
                searchHouseVos.add(searchHouseVo);
            }
        } catch (IOException e) {
            throw new HouseException(HttpCodeEnum.ERROR);
        }

//        return houseMapper.searchHouseList(addr);
        return searchHouseVos;
    }
    @Override
    public void addSellers(House house) {
        String userId = BaseContext.getCurrentId();
        house.setUserId(userId);
        house.setCreateDate(new Date(System.currentTimeMillis()));
        house.setCreatePerson(userId);
        house.setStates(Dictionaries.DEFAULT_HOUSE_STATES);
        LambdaQueryWrapper<House> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(House::getHouseId,house.getHouseId());
        houseMapper.delete(queryWrapper);
        DeleteRequest request = new DeleteRequest("house", house.getHouseId());
        try {
            restHighLevelClient.delete(request, RequestOptions.DEFAULT);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        houseMapper.insertHouse(house);
    }

    @Override
    public List<HouseVo> houseList(HouseLocationDto dto) {
        ArrayList<HouseVo> houseVos = new ArrayList<>();
        if (dto.getLongitude() != null && dto.getLatitude() != null) {
            String location = dto.getLatitude()+","+dto.getLongitude();
                SearchRequest request = new SearchRequest("house");
            if(dto.getDistance() != null){
                GeoDistanceQueryBuilder distanceQueryBuilder = new GeoDistanceQueryBuilder("location");
                distanceQueryBuilder
                        .point(Double.parseDouble(dto.getLatitude()), Double.parseDouble(dto.getLongitude()))
                        .distance(dto.getDistance(), DistanceUnit.KILOMETERS);
                request.source().query(distanceQueryBuilder);
            }
            SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
            sourceBuilder.size(50);
            sourceBuilder.sort(SortBuilders.geoDistanceSort("location",new GeoPoint(location))
                    .order(SortOrder.ASC)
                    .unit(DistanceUnit.METERS));
            request.source(sourceBuilder);

//            request.source().sort(QueryBuilders.)
            SearchResponse search = null;
            try {
                search = restHighLevelClient.search(request, RequestOptions.DEFAULT);
            } catch (IOException e) {
                throw new HouseException(HttpCodeEnum.ERROR);
            }
            for (SearchHit hit : search.getHits()){
                HouseVo houseVo = JSONUtil.toBean(hit.getSourceAsString(), HouseVo.class);
                double v = Double.parseDouble(hit.getSortValues()[0].toString());
                long round = Math.round(v);
                houseVo.setDistance(calculateDistance(round));
                houseVos.add(houseVo);
            }
        }else{
            // 准备Request
            SearchRequest request = new SearchRequest("house");
            // 组织DSL参数
            request.source()
                    .query(QueryBuilders.matchAllQuery());
            // 发送请求
            SearchResponse search = null;
            try {
                search = restHighLevelClient.search(request, RequestOptions.DEFAULT);
            } catch (IOException e) {
                throw new HouseException(HttpCodeEnum.ERROR);
            }
            for (SearchHit hit : search.getHits()){
                HouseVo houseVo = JSONUtil.toBean(hit.getSourceAsString(), HouseVo.class);
                houseVos.add(houseVo);
            }
        }
        return houseVos;
    }

    @Override
    public HouseInfoVo houseInfo(String houseId){

        HouseInfoVo houseInfoVo =houseMapper.houseInfo(houseId);
        String[] split = houseInfoVo.getEquipments().split(",");
        houseInfoVo.setEquipmentArr(split);
        // 查询当前房屋所以的图片信息
        List<String> images = houseImageMapper.selectHouseImageByHouseId(houseId);
        String headImage = houseInfoVo.getHeadImage();
        images.add(0,headImage);
        houseInfoVo.setImages(images);
        return houseInfoVo;

    }

    @Override
    public List<HouseVo> getHouseListById() {
        String userId = BaseContext.getCurrentId();
        List<HouseVo> houseListById = houseMapper.getHouseListById(userId);
        return houseListById;
    }

    @Override
    public House getHouseById(HouseDto dto) {
        LambdaQueryWrapper<House> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(House::getHouseId,dto.getHouseId());
        return houseMapper.selectOne(lambdaQueryWrapper);
    }

    @Override
    public boolean isHouseByOneself(String userId) {
        String myUserId = BaseContext.getCurrentId();
        return !myUserId.equals(userId);
    }

    @Override
    public Set<Object> getHotSearch() {
        return redisTemplate.opsForZSet().reverseRange(RedisContext.HOTSEARCH, 0, 7);
    }

    @Override
    public HouseVo getHouseVoOne(String houseId) {
        HouseVo houseVo = houseMapper.selectHouseVoOne(houseId);
        return houseVo;
    }

    public String calculateDistance(Long d){
        if (d >= 1000) {
            if (d >= 10000){
                DecimalFormat decimalFormat = new DecimalFormat("0.0");
                String format = decimalFormat.format(d * 1.0 / 1000);
                return format+"km";
            }else {
                DecimalFormat decimalFormat = new DecimalFormat("0.00");
                String format = decimalFormat.format(d * 1.0 / 1000);
                return format+"km";
            }

        }else {
            return d + "m";
        }
    }

}
